/**
 * Created by PanJiaChen on 16/11/18.
 */

/**
 * Parse the time to string
 * @param {(Object|string|number)} time
 * @param {string} cFormat
 * @returns {string | null}
 */
export function parseTime(time, cFormat) {
  if (arguments.length === 0 || !time) {
    return null
  }
  const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
  let date
  if (typeof time === 'object') {
    date = time
  } else {
    if ((typeof time === 'string')) {
      if ((/^[0-9]+$/.test(time))) {
        // support "1548221490638"
        time = parseInt(time)
      } else {
        // support safari
        // https://stackoverflow.com/questions/4310953/invalid-date-in-safari
        time = time.replace(new RegExp(/-/gm), '/')
      }
    }

    if ((typeof time === 'number') && (time.toString().length === 10)) {
      time = time * 1000
    }
    date = new Date(time)
  }
  const formatObj = {
    y: date.getFullYear(),
    m: date.getMonth() + 1,
    d: date.getDate(),
    h: date.getHours(),
    i: date.getMinutes(),
    s: date.getSeconds(),
    a: date.getDay()
  }
  const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => {
    const value = formatObj[key]
    // Note: getDay() returns 0 on Sunday
    if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] }
    return value.toString().padStart(2, '0')
  })
  return time_str
}

/**
 * @param {number} time
 * @param {string} option
 * @returns {string}
 */
export function formatTime(time, option) {
  if (('' + time).length === 10) {
    time = parseInt(time) * 1000
  } else {
    time = +time
  }
  const d = new Date(time)
  const now = Date.now()

  const diff = (now - d) / 1000

  if (diff < 30) {
    return '刚刚'
  } else if (diff < 3600) {
    // less 1 hour
    return Math.ceil(diff / 60) + '分钟前'
  } else if (diff < 3600 * 24) {
    return Math.ceil(diff / 3600) + '小时前'
  } else if (diff < 3600 * 24 * 2) {
    return '1天前'
  }
  if (option) {
    return parseTime(time, option)
  } else {
    return (
      d.getMonth() +
      1 +
      '月' +
      d.getDate() +
      '日' +
      d.getHours() +
      '时' +
      d.getMinutes() +
      '分'
    )
  }
}

/**
 * @param {string} url
 * @returns {Object}
 */
export function param2Obj(url) {
  const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
  if (!search) {
    return {}
  }
  const obj = {}
  const searchArr = search.split('&')
  searchArr.forEach(v => {
    const index = v.indexOf('=')
    if (index !== -1) {
      const name = v.substring(0, index)
      const val = v.substring(index + 1, v.length)
      obj[name] = val
    }
  })
  return obj
}

/**
 * 树查找
 * @param tree
 * @param id
 * @returns {null}
 */
export function deepQuery(tree, name) {
  var isGet = false
  var retNode = null
  function deepSearch(tree, name) {
    for (var i = 0; i < tree.length; i++) {
      if (tree[i].children && tree[i].children.length > 0) {
        deepSearch(tree[i].children, name)
      }
      if (name === tree[i].name || isGet) {
        isGet || (retNode = tree[i])
        isGet = true
        break
      }
    }
  }
  deepSearch(tree, name)
  return retNode
}

/**
 * 树过滤
 */

let _expandKeys_ = []
const defaultOpenKeyArr = []

export const filterTree = (val, tree, newArr = []) => {
  if (!(tree.length && val)) { // 如果搜索关键字为空直接返回源数据
    _expandKeys_ = defaultOpenKeyArr // 这块是为了记录tree的展开key可以忽略

    return tree
  }

  for (const item of tree) {
    if (item.name.includes(val)) { // 匹配到关键字的逻辑
      newArr.push(item) // 如果匹配到就在数值中添加记录

      if (item.children) _expandKeys_.push(item.key) // 这块是为了记录tree的展开key可以忽略

      continue // 匹配到了就退出循环了此时如果有子集也会一并带着
    }

    if (item.children && item.children.length) { // 如果父级节点没有匹配到就看看是否有子集，然后做递归
      _expandKeys_.push(item.key) // 这块是为了记录tree的展开key可以忽略

      const subArr = filterTree(val, item.children) // 缓存递归后的子集数组

      if (subArr && subArr.length) { // 如果子集数据有匹配到的节点
        const node = { ...item, children: subArr } // 关键逻辑，缓存父节点同时将递归后的子节点作为新值

        newArr.push(node) // 添加进数组
      }
    }
  }

  return newArr
}

/**
 * 列表转树
 */

export function listToTree(data, key = 'id', pKey = 'parentId') {
  const res = [];
  data.forEach((item) => {
    const parent = data.find((node) => node[key] === item[pKey]);
    if (parent) {
      parent.children = parent.children || [];
      parent.children.push(item);
    } else {
      // * 根节点
      res.push(item);
    }
  });
  return res;
}

export const dateFormat = (fmt, date) => {
  let ret;
  const opt = {
    'y+': date.getFullYear().toString(), // 年
    'M+': (date.getMonth() + 1).toString(), // 月
    'd+': date.getDate().toString(), // 日
    'H+': date.getHours().toString(), // 时
    'm+': date.getMinutes().toString(), // 分
    'S+': date.getSeconds().toString() // 秒
    // 有其他格式化字符需求可以继续添加，必须转化成字符串
  };
  for (const k in opt) {
    ret = new RegExp('(' + k + ')').exec(fmt);
    if (ret) {
      fmt = fmt.replace(
        ret[1],
        ret[1].length == 1 ? opt[k] : opt[k].padStart(ret[1].length, '0')
      );
    }
  }
  return fmt;
}

// 获取当前时间7天或30天
export const timeForMat = function(count) {
  // 拼接时间
  const time1 = new Date()
  time1.setTime(time1.getTime() - (24 * 60 * 60 * 1000))
  const Y1 = time1.getFullYear()
  const M1 = ((time1.getMonth() + 1) > 10 ? (time1.getMonth() + 1) : '0' + (time1.getMonth() + 1))
  const D1 = (time1.getDate() > 10 ? time1.getDate() : '0' + time1.getDate())
  const timer1 = Y1 + '-' + M1 + '-' + D1 // 当前时间
  const time2 = new Date()
  time2.setTime(time2.getTime() - (24 * 60 * 60 * 1000 * count))
  const Y2 = time2.getFullYear()
  const M2 = ((time2.getMonth() + 1) > 9 ? (time2.getMonth() + 1) : '0' + (time2.getMonth() + 1))
  const D2 = (time2.getDate() > 9 ? time2.getDate() : '0' + time2.getDate());
  const timer2 = Y2 + '-' + M2 + '-' + D2 // 之前的7天或者30天
  return {
    t1: timer1,
    t2: timer2
  }
  // 　　return Y2 + '-' + M2 + '-' + D2 + ' 00:00:00';
}

var earthRadiusMeters = 6371000.0;
var metersPerDegree = 2.0 * Math.PI * earthRadiusMeters / 360.0;
var radiansPerDegree = Math.PI / 180.0;
var degreesPerRadian = 180.0 / Math.PI;

/**
 * 计算平方米
 * points: [[x,y],[x,y]]
 * 或者
 * [[{"lat":y,"lng":x},{"lat":y,"lng":x}]] // 这个是leaflet.getBoundary()
 * */
function calculateArea(points) {
  var pointArr = [];
  if (points.length > 2) { // 数组内两个以上元素，
    pointArr = points;
  } else {
    var tmp = points[0];
    for (var i = 0; i < tmp.length; i++) {
      pointArr.push([tmp[i].lng, tmp[i].lat]);
    }
  }
  if (pointArr.length > 2) { // 数组内3个以上元素，才能计算面积
    var areaMeters2 = PlanarPolygonAreaMeters2(pointArr);
    if (areaMeters2 > 1000000.0) {
      areaMeters2 = SphericalPolygonAreaMeters2(pointArr);
    }
    return areaMeters2;
  }
}

/* 球面多边形面积计算*/
function SphericalPolygonAreaMeters2(points) {
  var totalAngle = 0;
  for (var i = 0; i < points.length; i++) {
    var j = (i + 1) % points.length;
    var k = (i + 2) % points.length;
    totalAngle += Angle(points[i], points[j], points[k]);
  }
  var planarTotalAngle = (points.length - 2) * 180.0;
  var sphericalExcess = totalAngle - planarTotalAngle;
  if (sphericalExcess > 420.0) {
    totalAngle = points.length * 360.0 - totalAngle;
    sphericalExcess = totalAngle - planarTotalAngle;
  } else if (sphericalExcess > 300.0 && sphericalExcess < 420.0) {
    sphericalExcess = Math.abs(360.0 - sphericalExcess);
  }
  return sphericalExcess * radiansPerDegree * earthRadiusMeters * earthRadiusMeters;
}

/* 角度*/
function Angle(p1, p2, p3) {
  var bearing21 = Bearing(p2, p1);
  var bearing23 = Bearing(p2, p3);
  var angle = bearing21 - bearing23;
  if (angle < 0) {
    angle += 360;
  }
  return angle;
}

/* 方向*/
function Bearing(from, to) {
  var lat1 = from[1] * radiansPerDegree;
  var lon1 = from[0] * radiansPerDegree;
  var lat2 = to[1] * radiansPerDegree;
  var lon2 = to[0] * radiansPerDegree;
  var angle = -Math.atan2(Math.sin(lon1 - lon2) * Math.cos(lat2), Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon1 - lon2));
  if (angle < 0) {
    angle += Math.PI * 2.0;
  }
  angle = angle * degreesPerRadian;
  return angle;
}

/* 平面多边形面积*/
function PlanarPolygonAreaMeters2(points) {
  var a = 0;
  for (var i = 0; i < points.length; ++i) {
    var j = (i + 1) % points.length;
    var xi = points[i][0] * metersPerDegree * Math.cos(points[i][1] * radiansPerDegree);
    var yi = points[i][1] * metersPerDegree;
    var xj = points[j][0] * metersPerDegree * Math.cos(points[j][1] * radiansPerDegree);
    var yj = points[j][1] * metersPerDegree;
    a += xi * yj - xj * yi;
  }
  return Math.abs(a / 2);
}

/** 计算亩 */
export const calculateAreaInMu = (points) => {
  return ((calculateArea(points) / 666.66).toFixed(1) + '');
}

function LngLat(longitude, latitude) {
  this.longitude = longitude;
  this.latitude = latitude;
}

function calculateLineDistance(start, end) {
  var d1 = 0.01745329251994329;
  var d2 = start.longitude;
  var d3 = start.latitude;
  var d4 = end.longitude;
  var d5 = end.latitude;
  d2 *= d1;
  d3 *= d1;
  d4 *= d1;
  d5 *= d1;
  var d6 = Math.sin(d2);
  var d7 = Math.sin(d3);
  var d8 = Math.cos(d2);
  var d9 = Math.cos(d3);
  var d10 = Math.sin(d4);
  var d11 = Math.sin(d5);
  var d12 = Math.cos(d4);
  var d13 = Math.cos(d5);
  var arrayOfDouble1 = [];
  var arrayOfDouble2 = [];
  arrayOfDouble1.push(d9 * d8);
  arrayOfDouble1.push(d9 * d6);
  arrayOfDouble1.push(d7);
  arrayOfDouble2.push(d13 * d12);
  arrayOfDouble2.push(d13 * d10);
  arrayOfDouble2.push(d11);
  var d14 = Math.sqrt((arrayOfDouble1[0] - arrayOfDouble2[0]) *
    (arrayOfDouble1[0] - arrayOfDouble2[0]) +
    (arrayOfDouble1[1] - arrayOfDouble2[1]) *
    (arrayOfDouble1[1] - arrayOfDouble2[1]) +
    (arrayOfDouble1[2] - arrayOfDouble2[2]) *
    (arrayOfDouble1[2] - arrayOfDouble2[2]));

  return (Math.asin(d14 / 2.0) * 12742001.579854401);
}
var start = new LngLat(116.368904, 39.923423);
var end = new LngLat(116.387271, 39.922501);

// 计算周长面积
export const workDistance = (arr) => {
  var distance = 0;
  for (var i = 0; i < arr.length; i++) {
    if (i == (arr.length - 1)) {
      distance += calculateLineDistance(arr[i], arr[0]);
    } else {
      distance += calculateLineDistance(arr[i], arr[i + 1]);
    }
    // console.log(calculateLineDistance(arr[i],arr[i+1])+'==='+i);
  }
  // console.log(calculateLineDistance(arr[arr.length-1],arr[0]));
  // distance+=calculateLineDistance(arr[arr.length-1],arr[0]);
  return distance;
}
// 验证手机
// export const checkPhoneThree=function (phone) {
//     var isPhone = /^(0|86|17951)?(1[3456789][0-9])[0-9]{8}$/;
//     var value = $(phone).val().trim();
//     if (isPhone.test(value)) {
//         return true;
//     } else {
//        // $(phone).val("");
//         alert("请输入正确的手机");
//     }
// },

/* 信息脱敏通用方法 */
export const hideSensitiveData = (str, frontLen, endLen) => {
  const len = str.length - frontLen - endLen;
  let xing = '';
  for (var i = 0; i < len; i++) {
    xing += '*';
  }
  return str.substring(0, frontLen) + xing + str.substring(str.length - endLen);
}

/** 按类型进行信息脱敏  str: 需要脱敏的信息, type: 信息类型
 * 1:证件号码 2:银行卡号 3:手机号码
 * 4:姓名（如果要隐藏的话） 5:固定电话号码 6:邮箱 10:其他*/
export const hideInfoByType = (str, type) => {
  if (!str) return ''
  switch (type) {
    case 1: // 证件号码 （身份证号、军官证号、护照号 身份证号）
      return hideSensitiveData(str, 1, 1)

    case 2: // 银行卡号
      return hideSensitiveData(str, 6, 4)

    case 3: // 手机号码
      return hideSensitiveData(str, 3, 4)

    case 4: // 姓名
      return hideSensitiveData(str, 0, str.length - 1)

    case 5: // 固定电话号码
      return hideSensitiveData(str, 4, 4)

    case 6: // 邮箱
      const index = str.indexOf('@')
      if (index == -1) {
        return ''
      }
      const str1 = str.substring(0, index + 1)
      if (str1.length > 3) {
        return str.substring(0, 3) + '***' + str.substring(str.length - (str.length - index));
      } else {
        return str.substring(0, index) + '***' + str.substring(str.length - (str.length - index));
      }

    case 10: // 其他类型的敏感信息
      return hideSensitiveData(str, parseInt(str.length / 3), parseInt(str.length / 3))

    default:
      break;
  }
}

export const DateAdd = (interval, number, date) => {
  /*
    *   功能:实现VBScript的DateAdd功能.
    *   参数:interval,字符串表达式，表示要添加的时间间隔.
    *   参数:number,数值表达式，表示要添加的时间间隔的个数.
    *   参数:date,时间对象.
    *   返回:新的时间对象.
    *   var   now   =   new   Date();
    *   var   newDate   =   DateAdd( "d ",5,now);
    *---------------   DateAdd(interval,number,date)   -----------------
    */
  switch (interval) {
    case 'y ': {
      date.setFullYear(date.getFullYear() + number);
      return date;
      break;
    }
    case 'q ': {
      date.setMonth(date.getMonth() + number * 3);
      return date;
      break;
    }
    case 'm ': {
      date.setMonth(date.getMonth() + number);
      return date;
      break;
    }
    case 'w ': {
      date.setDate(date.getDate() + number * 7);
      return date;
      break;
    }
    case 'd ': {
      date.setDate(date.getDate() + number);
      return date;
      break;
    }
    case 'h ': {
      date.setHours(date.getHours() + number);
      return date;
      break;
    }
    case 'm ': {
      date.setMinutes(date.getMinutes() + number);
      return date;
      break;
    }
    case 's ': {
      date.setSeconds(date.getSeconds() + number);
      return date;
      break;
    }
    default: {
      date.setDate(d.getDate() + number);
      return date;
      break;
    }
  }
}

/**
 * 防抖
 * @param {Function} func 要执行的回调函数
 * @param {Number} wait 延时的时间
 * @param {Boolean} immediate 是否立即执行
 * @return null
 */
let timeout;
export const Debounce = (func, wait = 300, immediate = false) => {
  // 清除定时器
  if (timeout !== null) clearTimeout(timeout);
  // 立即执行
  if (immediate) {
    var callNow = !timeout;
    timeout = setTimeout(function() {
      timeout = null;
    }, wait);
    if (callNow) typeof func === 'function' && func();
  } else {
    // 设置定时器，当最后一次操作后，timeout不会再被清除，所以在延时wait毫秒后执行func回调方法
    timeout = setTimeout(function() {
      typeof func === 'function' && func();
    }, wait);
  }
}

export default {
  DateAdd,
  Debounce
}
